package com.roncoo.eshop.inventory.service.impl;

import java.util.concurrent.ArrayBlockingQueue;

import org.springframework.stereotype.Service;

import com.roncoo.eshop.inventory.request.ProductInventoryDBUpdateRequest;
import com.roncoo.eshop.inventory.request.Request;
import com.roncoo.eshop.inventory.request.RequestQueue;
import com.roncoo.eshop.inventory.service.RequestAsyncProcessService;

import lombok.extern.slf4j.Slf4j;

/**
 * Copyright: Copyright (c) 2019 Hu-Cheng
 * 
 * @ClassName: RequestAsyncProcessServiceImpl.java
 * @Description: 请求异步执行service 实现类
 *
 * @version: v1.0.0
 * @author: hucheng
 * @date: 2019年9月19日 下午3:10:52
 *
 */
@Slf4j
@Service
public class RequestAsyncProcessServiceImpl implements RequestAsyncProcessService {

	@Override
	public void process(Request request) {

		try {

			if (request instanceof ProductInventoryDBUpdateRequest) {
				log.info("更新请求 >>>>>> 商品id：" + request.getProductId());
			} else {
				log.info("读取请求 >>>>>> 商品id：" + request.getProductId());
			}

			// 做请求的路由，根据每个商品id的请求，路由到对应的队列中去
			ArrayBlockingQueue<Request> queue = getRoutingQueue(request.getProductId());
			// 将请求放入到路由中
			queue.put(request);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}

	private ArrayBlockingQueue<Request> getRoutingQueue(Integer productId) {
		RequestQueue requestQueue = RequestQueue.getInstance();

		// 先获取productId的hash值
		String key = String.valueOf(productId);
		int h;
		int hash = (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);

		// 对hash值取模，将hash值路由到指定的内存队列中，比如内存队列大小8
		// 用内存队列的数量对hash值取模之后，结果一定是在0~7之间
		// 所以任何一个商品id都会被固定路由到同样的一个内存队列中去的
		int index = (requestQueue.queueSize() - 1) & hash;

		return requestQueue.getQueue(index);
	}

}
